home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Graphics⁄Sound / Macintosh Tracker Folder / Tracker Server Folder / mac_audio.c < prev    next >
Text File  |  1993-09-19  |  39KB  |  1,276 lines

  1. /* macintosh_audio.c */
  2.  
  3. /* All the stuff in this file was written by Thomas R. Lawrence. */
  4. /* See the "mac_readme" or "mac_programmer_info" files for more information */
  5. /* about the Macintosh port */
  6.  
  7. #include <Sound.h>
  8. #include <sane.h>
  9. #include "mac_event.h"
  10.  
  11. #include <math.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14.  
  15. #include "defs.h"
  16. #include "extern.h"
  17. #include "song.h"
  18. #include "channel.h"
  19.  
  20. #define CONSTRAIN(value,min,max) MAX(MIN(value,max),min)
  21.  
  22. #define MAXNUMBUFFERS (128)
  23. #define MAXBUFFERSIZE (8192)
  24. #define MinFreeMem (32768 + MAXBUFFERSIZE + 256)
  25.  
  26. /* comment this out to use C-code */
  27. #define USE_ASSEMBLY_CODE (1) /* 1 = yes, 0 = no */
  28.  
  29. typedef struct MyS
  30.     {
  31.         struct MyS*            Next; /* circular linked list embedded in a static array */
  32.         SndCommand            MySoundCommand;
  33.         SndCommand            MyCallbackCommand;
  34.         volatile short    InUseFlag; /* interrupt level flag; hence "volatile" */
  35.         ExtSoundHeader    Header;
  36.         char                        SampleArea[MAXBUFFERSIZE];
  37.     } MyStructure;
  38.  
  39. static pascal void        MyCallBack(SndChannel* Channel, SndCommand* Command);
  40.  
  41. extern Boolean                QuitPending;
  42.  
  43. static int                        mac_stereo;
  44. /* 256th of primary/secondary source for that side. */
  45. static int                        primary=256, secondary=0;
  46. extern short                    Loudness;
  47.  
  48. /* the following array is grouped as 16*256 2-byte words.    Bits 9..12 of the */
  49. /* index are the most significant bits of the fraction of the pointer for */
  50. /* anti-aliasing.    Bits 1..8 are the sample's value.    If Bit 0 of the address is */
  51. /* 0, then this is the partially weighted left hand side for the antialiasing */
  52. /* average.    Bit 0 == 1 is the right hand side.    The left hand side is */
  53. /* the fraction * sample.    The right hand side is 2s complement of fraction * sample */
  54. static char*                    AliasTable = NULL;
  55.  
  56. /* the following array is a 1024-byte array for converting samples overall loudness */
  57. /* with clipping instead of roll-over.    This is because each raw sample value */
  58. /* ranges from -128..127.    We convert this to unsigned for the table: 0..255 */
  59. /* There are 4 channels, so the maximum is 4*255 == 1020.    Thus, we provide */
  60. /* 1024 (a nice round number) values.    When the table is constructed, the */
  61. /* values are constrained (i.e. clipped) so that rollover doesn't occur.    This */
  62. /* makes the sound a bit better when the volume is high enough to cause */
  63. /* rollover.    The maximum value of abs(FinalVolumeTablePrimary) is "primary" */
  64. /* and the max of abs(FinalVolumeTableSecondary) is "secondary".    See */
  65. /* "resample" for usage notes */
  66. static char*                    FinalVolumeTablePrimary = NULL;
  67. static char*                    FinalVolumeTableSecondary = NULL;
  68.  
  69. /* the following array is a 0..64*256 entry array for converting volume */
  70. /* (in the upper bits) and an 8-bit sample value into a new sample value. */
  71. /* an upper value of 64 represents no scaling. */
  72. /* You use this like this: */
  73. /* SubVolumeTable[<8-bit sample> + 256 * <6-bit volume level>] */
  74. static short*                 SubVolumeTable = NULL;
  75.  
  76. /* the following array is used for workspace */
  77. static long                        WorkspaceBytes = 0;
  78. static short*                    WorkspaceArray1 = NULL;
  79. static short*                    WorkspaceArray2 = NULL;
  80.  
  81. static SndChannel*        MySoundChannel; /* here's where it all happens, folks */
  82.  
  83. static MyStructure*        Buffers[MAXNUMBUFFERS];
  84. static int                        ActualNumBuffers;
  85. static MyStructure*        CurrentBuffer;
  86. static int                        buf_index;
  87.  
  88. short                                    Pausing = false;
  89.  
  90. /* this is dragged in from "mac_event" */
  91. extern short                    NumBits; /* what they want */
  92. static int                        ActualNumBits; /* what we're actually using */
  93.  
  94.  
  95. /* this is called from the event cycle which is called from the synthesizer via */
  96. /* the invocation of "may_getchar()".    When the program is playing */
  97. /* (Pausing == false), it sets Pausing to true, pauses the Macintosh sound */
  98. /* channel, and then spinwaits, calling may_getchar to provide processing time */
  99. /* to other programs.    When the event to unpause is received, this program is */
  100. /* invoked again (the first activation record is still present--recursive */
  101. /* invocation).    The second call unpauses the sound channel and clears the flag. */
  102. /* As the call stack is unrolled, control will be returned here.    Since the */
  103. /* Pausing flag is now clear, this routine will exit and things will carry */
  104. /* on normaly.    FLAW:    pauseCmd does not seem to have an effect.    The buffered */
  105. /* sound will play out and sound will stop only when all prepared buffers */
  106. /* have been played.    I don't know how to fix this; it seems to be a problem in */
  107. /* the Macintosh OS, not in this program. */
  108. void                TogglePause(void)
  109.     {
  110.         SndCommand            MyCommand;
  111.  
  112.         if (Pausing)
  113.             {
  114.                 Pausing = false;
  115.                 MyCommand.cmd = resumeCmd;
  116.                 MyCommand.param1 = 0;
  117.                 MyCommand.param2 = 0;
  118.                 SndDoImmediate(MySoundChannel,&MyCommand);
  119.             }
  120.          else
  121.             {
  122.                 Pausing = true;
  123.                 MyCommand.cmd = pauseCmd;
  124.                 MyCommand.param1 = 0;
  125.                 MyCommand.param2 = 0;
  126.                 SndDoImmediate(MySoundChannel,&MyCommand);
  127.                 while (Pausing && !QuitPending)
  128.                     {
  129.                         may_getchar();
  130.                     }
  131.             }
  132.     }
  133.  
  134.  
  135. /* adjust the stereo mixing.    Percent is 0..100; each channel takes on a value */
  136. /* in 0..256, providing 8-bits of scaling.    At full volume for a channel, */
  137. /* 256 represents a shift left by 8.    Thus, a shift right by 8 is the necessary */
  138. /* correction after scaling.    "primary" is for the main channel and "secondary" */
  139. /* is for the other channel.    They do not correspond strictly to left and right. */
  140. void            set_mix(int percent)
  141.     {
  142.         percent *= (256/2);
  143.         percent /= 100;
  144.         secondary = percent;
  145.         primary = 256 - percent;
  146.     }
  147.  
  148.  
  149. /* recalibrate the volume lookup table using a new value.    This is done on */
  150. /* the fly as volume levels are adjusted. */
  151. void            ResetVolumeTable(void)
  152.     {
  153.         short                Scan;
  154.         short                Intermediate;
  155.         short                Radius;
  156.  
  157.         if (FinalVolumeTablePrimary == NULL)
  158.             {
  159.                 FinalVolumeTablePrimary = (char*)NewPtr(1024 * sizeof(char));
  160.                 if (FinalVolumeTablePrimary == NULL)
  161.                     {
  162.                         perror("Not enough memory to play song.");
  163.                         end_all();
  164.                     }
  165.             }
  166.         /* primary ranges between 0..255; abs(sample) ranges between 0..127. */
  167.         /* so we divide by 2 and subtract 1 just in case -128 gets in.    The radius */
  168.         /* is the maximum value we'll allow the sample to be.    Anything above */
  169.         /* is clipped.    Primary Radius + Secondary Radius == 127 (barring rounding */
  170.         /* errors.)    Thus we clip just before arithmetic rollover occurs. */
  171.         Radius = (primary / 2) - 1;
  172.         if (Radius < 0)
  173.             {
  174.                 Radius = 0;
  175.             }
  176.         for (Scan = -512; Scan <= 511; Scan += 1)
  177.             {
  178.                 Intermediate = (Scan * Loudness * primary) / (64 * 256);
  179.                 if (Intermediate > Radius)
  180.                     {
  181.                         Intermediate = Radius;
  182.                     }
  183.                 if (Intermediate < -Radius)
  184.                     {
  185.                         Intermediate = -Radius;
  186.                     }
  187.                 FinalVolumeTablePrimary[Scan & 0x03ff] = Intermediate;
  188.             }
  189.  
  190.         if (FinalVolumeTableSecondary == NULL)
  191.             {
  192.                 FinalVolumeTableSecondary = (char*)NewPtr(1024 * sizeof(char));
  193.                 if (FinalVolumeTableSecondary == NULL)
  194.                     {
  195.                         perror("Not enough memory to play song.");
  196.                         end_all();
  197.                     }
  198.             }
  199.         Radius = (secondary / 2) - 1;
  200.         if (Radius < 0)
  201.             {
  202.                 Radius = 0;
  203.             }
  204.         for (Scan = -512; Scan <= 511; Scan += 1)
  205.             {
  206.                 Intermediate = (Scan * Loudness * secondary) / (64 * 256);
  207.                 if (Intermediate > Radius)
  208.                     {
  209.                         Intermediate = Radius;
  210.                     }
  211.                 if (Intermediate < -Radius)
  212.                     {
  213.                         Intermediate = -Radius;
  214.                     }
  215.                 FinalVolumeTableSecondary[Scan & 0x03ff] = Intermediate;
  216.             }
  217.     }
  218.  
  219.  
  220. int                open_audio(int SampleRate, int StereoFlag)
  221.     {
  222.         OSErr                            Error;
  223.         short                            Scan;
  224.         short                            Index;
  225.         SndCommand                Cmd;
  226.         long double                Fred;
  227.         unsigned long            FixedSampleRate;
  228.         MyStructure*            LastBuffer;
  229.  
  230.         if ((NumBits != 8) && (NumBits != 16))
  231.             {
  232.                 NumBits = 8;
  233.             }
  234.         ActualNumBits = NumBits;
  235.         FixedSampleRate = ((long)SampleRate) << 16;
  236.         if (FixedSampleRate == 0)
  237.             {
  238.                 FixedSampleRate = rate22khz;
  239.             }
  240.  
  241.         if (AliasTable == NULL)
  242.             {
  243.                 AliasTable = (char*)NewPtr(16*256*2);
  244.                 if (AliasTable == NULL)
  245.                     {
  246.                         perror("Not enough memory to play song.");
  247.                         end_all();
  248.                     }
  249.                 for (Scan = 0; Scan <= 15; Scan += 1)
  250.                     {
  251.                         for (Index = -128; Index <= 127; Index += 1)
  252.                             {
  253.                                 short                TableIndex;
  254.  
  255.                                 /* we precompute the antialiasing multiplication table here. */
  256.                                 /* Scan == the high 4 bits of the fraction of the pointer which */
  257.                                 /* is accessing the sampled sound.    Thus 0 IS a sample point, */
  258.                                 /* 1 is just to the right of a sample point, and 15 is just to */
  259.                                 /* the left of a sample point.    As we approach the right, the */
  260.                                 /* value increases, so the right weight is just Scan.    As we */
  261.                                 /* approach the left, the weight increases, but Scan decreases */
  262.                                 /* so the value is 16-Scan.    When Scan == 0, the weight of the */
  263.                                 /* right is 0, and the full left value is used.    This is because */
  264.                                 /* at this point, the left sample is being pointed directly to */
  265.                                 /* so it's actual value should be returned. */
  266.                                 TableIndex = ((Scan << 8) | (Index & 0x00ff)) << 1;
  267.                                 AliasTable[TableIndex + 0] = ((16 - Scan) * Index) / 16;
  268.                                 AliasTable[TableIndex + 1] = (Scan * Index) / 16;
  269.                             }
  270.                     }
  271.             }
  272.  
  273.         ResetVolumeTable();
  274.  
  275.         if (SubVolumeTable == NULL)
  276.             {
  277.                 SubVolumeTable = (short*)NewPtr((MAX_VOLUME-MIN_VOLUME+1)*256*sizeof(short));
  278.                 if (SubVolumeTable == NULL)
  279.                     {
  280.                         perror("Not enough memory to play song.");
  281.                         end_all();
  282.                     }
  283.                 for (Scan = 0; Scan <= MAX_VOLUME - MIN_VOLUME; Scan += 1)
  284.                     {
  285.                         for (Index = -128; Index <= 127; Index += 1)
  286.                             {
  287.                                 SubVolumeTable[(Scan << 8) | (Index & 0x00ff)]
  288.                                     = ((Scan + MIN_VOLUME) * Index + ((MAX_VOLUME - MIN_VOLUME)/2))
  289.                                     / (MAX_VOLUME - MIN_VOLUME);
  290.                                 /* normally, that would be MAX_VOLUME - MIN_VOLUME + 1, but */
  291.                                 /* we want to be 0..1 instead of 0..0.99999 because MAX_VOLUME */
  292.                                 /* should not scale the volume at all. */
  293.                             }
  294.                     }
  295.             }
  296.  
  297.         mac_stereo = StereoFlag;
  298.  
  299.         Error = SndNewChannel(&MySoundChannel,
  300.             sampledSynth, /* what synthesizer to use */
  301.             (StereoFlag * initStereo)
  302.                 | initNoInterp, /* we do oversampling ourselves */
  303.             (void*)MyCallBack /* == our buffer unmarking callback routine */);
  304.         if (Error != noErr)
  305.             {
  306.                 perror("unable to open sound channel");
  307.                 end_all();
  308.             }
  309.         Cmd.cmd = ampCmd;
  310.         Cmd.param1 = 255;
  311.         Cmd.param2 = 0;
  312.         Error = SndDoImmediate(MySoundChannel,&Cmd);
  313.         if (Error != noErr)
  314.             {
  315.                 perror("unable to initialize sound channel");
  316.             }
  317.  
  318.         /* create an initial workspace */
  319.         WorkspaceBytes = (1500 * sizeof(short) + 3) & ~3L; /* should be plenty */
  320.         WorkspaceArray1 = (void*)NewPtr(WorkspaceBytes);
  321.         WorkspaceArray2 = (void*)NewPtr(WorkspaceBytes);
  322.         if ((WorkspaceArray1 == NULL) || (WorkspaceArray2 == NULL))
  323.             {
  324.                 FatalError(FatalErrorOutOfMemory);
  325.                 perror("No memory to allocate workspace.");
  326.                 end_all();
  327.             }
  328.  
  329.         /* we now try to make as many buffers as we have memory for, so we can */
  330.         /* precompute the composite samples to be played as far ahead as we can */
  331.         /* so that momentary losses of control don't make the sound skip.    We */
  332.         /* need at least 3 buffers, for double buffering and to make our full */
  333.         /* usage check work.    (We check to see if all buffers are waiting to be played */
  334.         /* and not empty by counting the number of ones with a marked "InUseFlag" */
  335.         /* However, one buffer (the one under construction) will always be NOT */
  336.         /* marked.    If we settle for 2 buffers, then when we account for the buffer */
  337.         /* we are constructing, it will always look like all buffers are in use */
  338.         /* until all have stopped.    The sound will skip, so we might as well not */
  339.         /* play it at all.    Hence the limit of 3 buffers.) */
  340.         Scan = 0;
  341.         do
  342.             {
  343.                 MyStructure*            Temp;
  344.                 long                            FreeMemory;
  345.  
  346.                 FreeMemory = FreeMem();
  347.                 if (FreeMemory < MinFreeMem)
  348.                     {
  349.                         if (Scan < 3)
  350.                             {
  351.                                 perror("Not enough memory to play song!");
  352.                                 FatalError(FatalErrorOutOfMemory);
  353.                                 FatalError(FatalErrorOutOfMemory);
  354.                                 end_all();
  355.                             }
  356.                          else
  357.                             {
  358.                                 goto StopMakingBuffers;
  359.                             }
  360.                     }
  361.                 Buffers[Scan] = (void*)NewPtr(sizeof(MyStructure));
  362.                 Buffers[Scan]->InUseFlag = 0;
  363.                 Buffers[Scan]->Header.samplePtr = &(Buffers[Scan]->SampleArea[0]);
  364.                 if (mac_stereo)
  365.                     {
  366.                         Buffers[Scan]->Header.sampleSize = ActualNumBits;
  367.                         Buffers[Scan]->Header.numChannels = 2;
  368.                     }
  369.                  else
  370.                     {
  371.                         Buffers[Scan]->Header.sampleSize = ActualNumBits;
  372.                         Buffers[Scan]->Header.numChannels = 1;
  373.                     }
  374.                 Buffers[Scan]->Header.sampleRate = FixedSampleRate;
  375.                 Buffers[Scan]->Header.loopStart = 0;
  376.                 Buffers[Scan]->Header.loopEnd = 0;
  377.                 Buffers[Scan]->Header.encode = extSH;
  378.                 Buffers[Scan]->Header.baseFrequency = 64;
  379.                 Buffers[Scan]->Header.markerChunk = NULL;
  380.                 Buffers[Scan]->Header.futureUse1 = 0;
  381.                 Buffers[Scan]->Header.futureUse2 = 0;
  382.                 Buffers[Scan]->Header.futureUse3 = 0;
  383.                 Buffers[Scan]->Header.futureUse4 = 0;
  384.                 Fred = SampleRate;
  385.                 x96tox80(&Fred,&(Buffers[Scan]->Header.AIFFSampleRate));
  386.                 Scan += 1;
  387.             } while (Scan < MAXNUMBUFFERS);
  388.      StopMakingBuffers:
  389.         ActualNumBuffers = Scan;
  390.         for (Scan = 0; Scan < ActualNumBuffers; Scan += 1)
  391.             {
  392.                 /* now we establish the circular linked list so that we can */
  393.                 /* easily find out what the "next" buffer to use is */
  394.                 Buffers[Scan]->Next = Buffers[(Scan + 1) % ActualNumBuffers];
  395.             }
  396.         CurrentBuffer = Buffers[0];
  397.         buf_index = 0;
  398.  
  399.         return FixedSampleRate >> 16;
  400.     }
  401.  
  402.  
  403. /* this evaluates to see if all but the current buffer have been filled */
  404. /* and are waiting to be played.    If they have, then we can take a break in */
  405. /* the event loop since there won't be any work to do for a while. */
  406. BOOL            is_channel_full(void)
  407.     {
  408.         int                    Scan;
  409.         int                    Count;
  410.  
  411.         Count = 0;
  412.         for (Scan = 0; Scan < ActualNumBuffers; Scan += 1)
  413.             {
  414.                 if (Buffers[Scan]->InUseFlag)
  415.                     {
  416.                         Count += 1;
  417.                     }
  418.             }
  419.         if (Count >= ActualNumBuffers - 1)
  420.             {
  421.                 return TRUE;
  422.             }
  423.          else
  424.              {
  425.                  return FALSE;
  426.              }
  427.     }
  428.  
  429.  
  430. /* here we check to see if all the buffers have played out.    This is done */
  431. /* at the end so that we don't close the channel too early and cut off the */
  432. /* end of the song. */
  433. BOOL            is_channel_empty(void)
  434.     {
  435.         int                    Scan;
  436.  
  437.         for (Scan = 0; Scan < ActualNumBuffers; Scan += 1)
  438.             {
  439.                 if (Buffers[Scan]->InUseFlag)
  440.                     {
  441.                         return FALSE; /* nope, buffers are still in use */
  442.                     }
  443.             }
  444.         return TRUE;
  445.     }
  446.  
  447.  
  448. /* this counts the number of buffers waiting to be played.    The event loop uses */
  449. /* this to get an idea of how long it can sit around before worrying about */
  450. /* filling some more buffers. */
  451. short                NumberPendingBlocks(void)
  452.     {
  453.         int                    Scan;
  454.         int                    Count;
  455.  
  456.         Count = 0;
  457.         for (Scan = 0; Scan < ActualNumBuffers; Scan += 1)
  458.             {
  459.                 if (Buffers[Scan]->InUseFlag)
  460.                     {
  461.                         Count += 1;
  462.                     }
  463.             }
  464.         return Count;
  465.     }
  466.  
  467.  
  468. /* queues the data to be played by the sound manager. */
  469. void            actually_flush_buffer(void)
  470.     {
  471.         OSErr                    Error;
  472.  
  473.         while (CurrentBuffer->Next->InUseFlag)
  474.             {
  475.                 /* since the list is a circular list, the next element is the "oldest" */
  476.                 /* element.    If it is full, then all the others are too, so we just wait. */
  477.                 /* if all the buffers have been filled, then we'll just spinwait */
  478.                 /* here for 0.25 of a second waiting for one to play out.    This could */
  479.                 /* be a problem.    If the number of buffers is small, then they might */
  480.                 /* appear to be full, but they could still play out in less than 0.25 */
  481.                 /* of a second.    See also "may_getchar" where a similar thing is done. */
  482.                 WaitForEvent(15);
  483.             }
  484.  
  485.      TryAgainPoint1:
  486.         CurrentBuffer->InUseFlag = 1;
  487.         CurrentBuffer->MySoundCommand.cmd = bufferCmd;
  488.         CurrentBuffer->MySoundCommand.param1 = 0;
  489.         CurrentBuffer->MySoundCommand.param2 = (long)&(CurrentBuffer->Header);
  490.         if (mac_stereo)
  491.             {
  492.                 /* stereo sample frames have 2 "samples" in them, so the index */
  493.                 /* into the buffer is twice the number of frames. */
  494.                 CurrentBuffer->Header.numFrames = buf_index / (2 * (ActualNumBits / 8));
  495.             }
  496.          else
  497.             {
  498.                 CurrentBuffer->Header.numFrames = buf_index / (1 * (ActualNumBits / 8));
  499.             }
  500.         Error = SndDoCommand(MySoundChannel,&(CurrentBuffer->MySoundCommand),1);
  501.         if (queueFull == Error)
  502.             {
  503.                 WaitForEvent(2);
  504.                 goto TryAgainPoint1;
  505.             }
  506.  
  507.         /* the callback is an interrupt level thing that clears a buffer so */
  508.         /* we can use it again. */
  509.      TryAgainPoint2:
  510.         CurrentBuffer->MyCallbackCommand.cmd = callBackCmd;
  511.         CurrentBuffer->MyCallbackCommand.param2 = (long)&(CurrentBuffer->InUseFlag);
  512.         Error = SndDoCommand(MySoundChannel,&(CurrentBuffer->MyCallbackCommand),1);
  513.         if (queueFull == Error)
  514.             {
  515.                 WaitForEvent(2);
  516.                 goto TryAgainPoint2;
  517.             }
  518.  
  519.         buf_index = 0;
  520.         CurrentBuffer = CurrentBuffer->Next;
  521.     }
  522.  
  523.  
  524. /* this function is not actually used */
  525. void            output_samples(int left, int right)
  526.     {
  527.         /* in the normal tracker, this is called EVERY TIME a sample frame is */
  528.         /* output.    It normally results in a call to flush_buffer.    Since */
  529.         /* THINK C won't inline functions, this was way to slow, so I dispensed with it */
  530.     }
  531.  
  532.  
  533. /* this flushes the buffer IF another cycle would overflow it.    Since the number */
  534. /* of bytes added to the buffer is SamplingRate / Speed, at high sampling rates */
  535. /* or ridiculously low speeds, larger than the buffer size could be created in */
  536. /* just one call to "resample."    This would be BAD.    Therefore "resample" checks */
  537. /* for this and returns a fatal error if it would happen. */
  538. void            flush_buffer(int BytesGenerated)
  539.     {
  540.         if (buf_index + BytesGenerated >= MAXBUFFERSIZE - 1)
  541.             actually_flush_buffer();
  542.     }
  543.  
  544.  
  545. /* waiting for all samples to play and then closing sound channel & disposing buffers */
  546. void            close_audio(void)
  547.     {
  548.         int                        Scan;
  549.         EventRecord        StupidEvent;
  550.  
  551.         if (buf_index != 0)
  552.             {
  553.                 /* make sure that last 1/8 of a second worth of song gets played. */
  554.                 actually_flush_buffer();
  555.             }
  556.  
  557.         /* wait for all buffers to play out */
  558.         /* if we receive a quit event, we just go away */
  559.         /* but for end of song, we wait for the buffers to play out */
  560.         /* SndDisposeChannel does this, but we want to be friendly to other */
  561.         /* processes by calling WaitNextEvent(), so we do it ourselves. */
  562.         while (!QuitPending && !is_channel_empty())
  563.             {
  564.                 WaitForEvent(60);
  565.             }
  566.  
  567.         /* close macintosh sound channel, cancel any callbacks */
  568. #if 0
  569.         /* I used to be using this quietCmd which, according to the great Inside */
  570.         /* Macintosh VI, should stop all processing on the channel.    Unfortunately, */
  571.         /* when I perform the call, the channel promptly becomes useless and the */
  572.         /* system hangs in the SndDisposeChannel routine waiting for some event */
  573.         /* that'll never happen (I have no idea what, but MacsBug clearly shows the */
  574.         /* infinite loop in system code). */
  575.         if (QuitPending)
  576.             {
  577.                 SndCommand        Cmd;
  578.  
  579.                 Cmd.cmd = quietCmd;
  580.                 Cmd.param1 = 0;
  581.                 Cmd.param2 = 0;
  582.                 SndDoImmediate(MySoundChannel,&Cmd);
  583.             }
  584. #endif
  585.         /* if we are supposed to quit right away, then we send 1 as the second */
  586.         /* parameter to do it right away, otherwise it'll wait for everything to */
  587.         /* play out before closing the channel */
  588.         SndDisposeChannel(MySoundChannel,QuitPending);
  589.  
  590.         /* release memory allocated for buffers */
  591.         for (Scan = 0; Scan < ActualNumBuffers; Scan += 1)
  592.             {
  593.                 /* this isn't really necessary unless you play more than one song */
  594.                 /* at a time and the buffer is flushed each time. */
  595.                 DisposPtr((void*)Buffers[Scan]);
  596.             }
  597.     }
  598.  
  599.  
  600. /* what is this for? */
  601. void            set_synchro(int s)
  602.     {
  603.     }
  604.  
  605. /* another mystery function */
  606. int             update_frequency(void)
  607.     {
  608.         return 0;
  609.     }
  610.  
  611. void            discard_buffer(void)
  612.     {
  613.     }
  614.  
  615.  
  616. #if __option(profile)
  617. #define Profiling
  618. #endif
  619.  
  620. #pragma options(!profile)
  621.  
  622. /* asynchronous callback routine which marks buffers as now unused */
  623. /* It would be very bad to profile this since profiling tampers with the */
  624. /* stack invocation and uses A5 global variables!    (believe me, I've tried) */
  625. static pascal void        MyCallBack(SndChannel* Channel, SndCommand* Command)
  626.     {
  627.         *(short*)(Command->param2) = 0;
  628.     }
  629.  
  630. #ifdef Profiling
  631. #pragma options(profile)
  632. #endif
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641. /* stuff removed from "audio.c" */
  642.  
  643.  
  644. /* prototypes for my single channel resamplers have been added */
  645. void        SampleAntiAliased8(struct channel* ch, short* Buffer, short Count);
  646. void        SampleAliased8(struct channel* ch, short* Buffer, short Count);
  647. void        SampleAntiAliased16(struct channel* ch, short* Buffer, short Count);
  648. void        SampleAliased16(struct channel* ch, short* Buffer, short Count);
  649.  
  650.  
  651. /* a new "resample" function using my single channel resamplers has been added */
  652. void resample(struct channel *chan, int oversample, int number)
  653.     {
  654.         short                i;
  655.         short*            WA1Shadow;
  656.         short*            WA2Shadow;
  657.         short                BytesGenerated;
  658.  
  659.         /* flush the stuff to the buffer.    i.e. if we would overflow the */
  660.         /* buffer during this cycle, we flush it and get a new buffer. */
  661.         /* later on, checks are performed to make sure we won't overflow the buffer. */
  662.         /* the only time that would happen would be if BytesGenerated is bigger */
  663.         /* than the whole buffer. */
  664.         /* note that flush_buffer now takes a parameter */
  665.         if (mac_stereo)
  666.             {
  667.                 BytesGenerated = number * 2 * (ActualNumBits / 8);
  668.             }
  669.          else
  670.             {
  671.                 BytesGenerated = number * (ActualNumBits / 8);
  672.             }
  673.         flush_buffer(BytesGenerated);
  674.  
  675.         if (BytesGenerated + buf_index > MAXBUFFERSIZE)
  676.             {
  677.                 perror("Buffer size not set large enough");
  678.                 FatalError(FatalErrorInternalError);
  679.                 end_all();
  680.             }
  681.  
  682.         /* we need a workspace where we construct the channels before scaling */
  683.         /* the final volume.    If we need a bigger one than originally anticipated */
  684.         /* we attempt to reallocate it. */
  685.      Reallocate:
  686.         if (WorkspaceBytes == 0)
  687.             {
  688.                 /* workspace always holds 16-bit values */
  689.                 WorkspaceBytes = (number * sizeof(short) + 3) & ~3L;
  690.                 WorkspaceArray1 = (void*)NewPtr(WorkspaceBytes);
  691.                 WorkspaceArray2 = (void*)NewPtr(WorkspaceBytes);
  692.                 if ((WorkspaceArray1 == NULL) || (WorkspaceArray2 == NULL))
  693.                     {
  694.                         perror("Ran out of memory playing song.");
  695.                         FatalError(FatalErrorOutOfMemory);
  696.                         end_all();
  697.                     }
  698.             }
  699.          else
  700.             {
  701.                 if (WorkspaceBytes < ((number * sizeof(short) + 3) & ~3L))
  702.                     {
  703.                         DisposPtr((void*)WorkspaceArray1);
  704.                         DisposPtr((void*)WorkspaceArray2);
  705.                         WorkspaceBytes = 0;
  706.                         goto Reallocate;
  707.                     }
  708.             }
  709.  
  710.         /* first, erase the workspace, since SampleXXX adds to the workspace. */
  711.         WA1Shadow = WorkspaceArray1;
  712.         WA2Shadow = WorkspaceArray2;
  713.         for (i = WorkspaceBytes / sizeof(long) - 1; i >= 0; i -= 1)
  714.             {
  715.                 /* longs erase faster on 68030 */
  716.                 ((long*)WA1Shadow)[i] = 0;
  717.                 ((long*)WA2Shadow)[i] = 0;
  718.             }
  719.  
  720.         if (ActualNumBits == 8)
  721.             {
  722.                 char*            BufferAddress;
  723.  
  724.                 /* 8-bit sampling */
  725.  
  726.                 /* oversample == 1 is merely no antialiasing.    I didn't want to fiddle with */
  727.                 /* Espie's code, so I just use oversample instead of a new variable "antialiased" */
  728.                 if (oversample == 1)
  729.                     {
  730.                         /* WorkspaceArray1 is the left channel, WorkspaceArray2 is the right channel */
  731.                         SampleAliased8(&(chan[0]),WA1Shadow,number);
  732.                         SampleAliased8(&(chan[1]),WA2Shadow,number);
  733.                         SampleAliased8(&(chan[2]),WA2Shadow,number);
  734.                         SampleAliased8(&(chan[3]),WA1Shadow,number);
  735.                     }
  736.                  else
  737.                     {
  738.                         SampleAntiAliased8(&(chan[0]),WA1Shadow,number);
  739.                         SampleAntiAliased8(&(chan[1]),WA2Shadow,number);
  740.                         SampleAntiAliased8(&(chan[2]),WA2Shadow,number);
  741.                         SampleAntiAliased8(&(chan[3]),WA1Shadow,number);
  742.                     }
  743.                  /* notes about that stuff above:    workspace always holds 16-bit values, so */
  744.                  /* we don't have to fool with ActualNumBits to figure out how many bytes */
  745.                  /* the workspace should be. */
  746.  
  747.                 BufferAddress = &(CurrentBuffer->SampleArea[buf_index]);
  748.                 if (mac_stereo)
  749.                     {
  750.                         do
  751.                             {
  752.                                 /* Note how we add both the primary and secondary scaling tables. */
  753.                                 /* hence each table is independently clipped. */
  754.                                 /* left channel */
  755.                                 *(BufferAddress++) = FinalVolumeTablePrimary[(*WA1Shadow) & 0x03ff]
  756.                                     + FinalVolumeTableSecondary[(*WA2Shadow) & 0x03ff] + 128;
  757.                                 /* right channel */
  758.                                 *(BufferAddress++) = FinalVolumeTablePrimary[*(WA2Shadow++) & 0x03ff]
  759.                                     + FinalVolumeTableSecondary[*(WA1Shadow++) & 0x03ff] + 128;
  760.                                 number -= 1;
  761.                             } while (number > 0);
  762.                     }
  763.                  else
  764.                     {
  765.                         do
  766.                             {
  767.                                 /* for mono, we don't have any secondary sound coming in from */
  768.                                 /* the other channel. */
  769.                                 *(BufferAddress++) = FinalVolumeTablePrimary[(*(WA1Shadow++)
  770.                                     + *(WA2Shadow++)) & 0x03ff] + 128;
  771.                                 number -= 1;
  772.                             } while (number > 0);
  773.                     }
  774.             }
  775.          else
  776.             {
  777.                 short*            BufferAddress;
  778.  
  779.                 /* 16 bit sampling */
  780.  
  781.                 /* oversample == 1 is merely no antialiasing.    I didn't want to fiddle with */
  782.                 /* Espie's code, so I just use oversample instead of a new variable "antialiased" */
  783.                 if (oversample == 1)
  784.                     {
  785.                         /* WorkspaceArray1 is the left channel, WorkspaceArray2 is the right channel */
  786.                         SampleAliased16(&(chan[0]),WA1Shadow,number);
  787.                         SampleAliased16(&(chan[1]),WA2Shadow,number);
  788.                         SampleAliased16(&(chan[2]),WA2Shadow,number);
  789.                         SampleAliased16(&(chan[3]),WA1Shadow,number);
  790.                     }
  791.                  else
  792.                     {
  793.                         SampleAntiAliased16(&(chan[0]),WA1Shadow,number);
  794.                         SampleAntiAliased16(&(chan[1]),WA2Shadow,number);
  795.                         SampleAntiAliased16(&(chan[2]),WA2Shadow,number);
  796.                         SampleAntiAliased16(&(chan[3]),WA1Shadow,number);
  797.                     }
  798.                  /* notes about that stuff above:    workspace always holds 16-bit values, so */
  799.                  /* we don't have to fool with ActualNumBits to figure out how many bytes */
  800.                  /* the workspace should be. */
  801.  
  802.                 BufferAddress = (short*)&(CurrentBuffer->SampleArea[buf_index]);
  803.                 if (mac_stereo)
  804.                     {
  805.                         short                PrimaryV;
  806.                         short                SecondaryV;
  807.  
  808.                         PrimaryV = primary * Loudness;
  809.                         SecondaryV = secondary * Loudness;
  810.                         do
  811.                             {
  812.                                 /* left channel */
  813.                                 /* Primary + Secondary = 256; each buffer has -16384..16383 */
  814.                                 /* in it, Loudness could be 64, so we need to divide by 256*64 */
  815.                                 /* (16384; shift left by 14) */
  816.                                 *(BufferAddress++) = (short)((((*WA1Shadow) * PrimaryV)
  817.                                     + ((*WA2Shadow) * SecondaryV)) >> 14) /*+ (short)0x8000*/;
  818.                                 /* right channel */
  819.                                 *(BufferAddress++) = (short)((((*(WA2Shadow++)) * PrimaryV)
  820.                                     + ((*(WA1Shadow++)) * SecondaryV)) >> 14) /*+ (short)0x8000*/;
  821.                                 number -= 1;
  822.                             } while (number > 0);
  823.                     }
  824.                  else
  825.                     {
  826.                         short                LocalLoudness;
  827.  
  828.                         LocalLoudness = Loudness;
  829.                         do
  830.                             {
  831.                                 /* Loudness could be as high as 64, and the buffers have */
  832.                                 /* -16384..16383, which, added together, is -32768..32767 */
  833.                                 /* so we need to divide by 64 (shift left by 6) */
  834.                                 *(BufferAddress++) = (short)(
  835.                                     (((long)*(WA1Shadow++) + (long)*(WA2Shadow++)) * LocalLoudness)
  836.                                     >> 6) /*+ (short)0x8000*/;
  837.                                 number -= 1;
  838.                             } while (number > 0);
  839.                     }
  840.             }
  841.  
  842.         buf_index += BytesGenerated; /* account for added bytes */
  843.     }
  844.  
  845.  
  846. /* the actual functions for single-channel resampling */
  847.  
  848.  
  849. #if !USE_ASSEMBLY_CODE
  850. void            SampleAliased8(struct channel* ch, short* Buffer, short Count)
  851.     {
  852.         long                Pointer;
  853.         long                FixLength;
  854.         char*                SampleData;
  855.         long                Step;
  856.         long                LoopLength;
  857.         short                Volume;
  858.  
  859.         if (ch->mode != DO_NOTHING)
  860.             {
  861.                 Pointer = ch->pointer;
  862.                 FixLength = ch->samp->fix_length;
  863.                 SampleData = ch->samp->start;
  864.                 Step = ch->step;
  865.                 LoopLength = ch->samp->fix_rp_length;
  866.                 Volume = CONSTRAIN(ch->volume,MIN_VOLUME,MAX_VOLUME) - MIN_VOLUME;
  867.              LoopPoint:
  868.                 if (Pointer >= FixLength)
  869.                     {
  870.                         /* is there a replay ? */
  871.                         if (!ch->samp->rp_start)
  872.                             {
  873.                                 ch->mode = DO_NOTHING;
  874.                                 goto OutPoint;
  875.                             }
  876.                         ch->mode = REPLAY;
  877.                         Pointer -= LoopLength;
  878.                         goto LoopPoint;
  879.                     }
  880.                 *(Buffer++) += (Volume * SampleData[fix_to_int(Pointer)]) >> 6;
  881.                 Pointer += Step;
  882.                 Count -= 1;
  883.                 if (Count > 0)
  884.                     {
  885.                         goto LoopPoint;
  886.                     }
  887.              OutPoint:
  888.                 ch->pointer = Pointer;
  889.             }
  890.     }
  891. #else
  892. void            SampleAliased8(struct channel* ch, short* Buffer, short Count)
  893.     {
  894.         #define Pointer    D0
  895.         #define Step    D1
  896.         #define FixLength    D2
  897.         #define LocalCount    D3
  898.         #define Temp    D4
  899.         #define Temp2    D5
  900.  
  901.         #define SampleData    A0
  902.         #define VolumeMap    A1
  903.         #define Channel    A2
  904.         #define SampPtr    A3
  905.         #define LocalBuffer    A4
  906.  
  907.         asm
  908.             {
  909.                 movem.l            D3-D5/A2-A4,-(A7)
  910.  
  911.                 /* loading global variables & parameters:    Must NOT disturb A5 and A6 here */
  912.                 move.l            ch,Channel
  913.                 move.w            Count,LocalCount
  914.                 move.l            OFFSET(struct channel,volume)(Channel),Temp    ;got volume
  915.                 cmp.l                #MIN_VOLUME,Temp
  916.                 bge.s                @8
  917.                 moveq.l            #0,Temp    ;if volume < 0, constrain it to 0
  918.         @8: cmp.l                #MAX_VOLUME,Temp
  919.                 bmi.s                @7
  920.                 moveq.l            #MAX_VOLUME,Temp    ;if volume > max volume, constain it to max
  921.         @7:
  922. #if 0 != MIN_VOLUME
  923.                 ;this bit is untested, but I think it will work.    Don't see why
  924.                 ;MIN_VOLUME would ever be != 0, though
  925.                 add.l                #(MIN_VOLUME * 256 * sizeof(short)),Temp    ;table starts at 0, so add this in
  926. #endif
  927.                 moveq                #9,Temp2
  928.                 lsl.l                Temp2,Temp    ;multiplied by 256*sizeof(short) to obtain offset
  929.                 move.l            SubVolumeTable,VolumeMap    ;get base address
  930.                 add.l                Temp,VolumeMap    ;add offset
  931.                 move.l            Buffer,LocalBuffer
  932.                 subq.w            #1,LocalCount
  933.                 /* loading sample things */
  934.                 move.l            OFFSET(struct channel,samp)(Channel),SampPtr
  935.                 move.l            OFFSET(struct sample_info,fix_length)(SampPtr),FixLength
  936.                 move.l            OFFSET(struct sample_info,start)(SampPtr),SampleData
  937.                 /* loading channel things */
  938.                 move.l            OFFSET(struct channel,pointer)(Channel),Pointer
  939.                 move.l            OFFSET(struct channel,step)(Channel),Step
  940.                 /* clearing high bits of certain registers */
  941.  
  942.                 cmp.l                #DO_NOTHING,OFFSET(struct channel,mode)(Channel)
  943.                 beq.s                @OutPoint
  944.  
  945.         @3: cmp.l                Pointer,FixLength
  946.                 bhi.s                @1
  947.                 tst.l                OFFSET(struct sample_info,rp_start)(SampPtr)
  948.                 bne.s                @2
  949.                 move.l            #DO_NOTHING,OFFSET(struct channel,mode)(Channel)
  950.                 bra.s                @OutPoint
  951.         @2: sub.l                OFFSET(struct sample_info,fix_rp_length)(SampPtr),Pointer
  952.                 move.l            #REPLAY,OFFSET(struct channel,mode)(Channel)
  953.                 bra.s                @3
  954.  
  955.         @1:
  956.                 move.l            Pointer,Temp
  957.                 moveq                #ACCURACY,Temp2
  958.                 lsr.l                Temp2,Temp    ;now Temp is the data index
  959.                 moveq.l            #0,Temp2
  960.                 move.b            0(SampleData,Temp.L),Temp2    ;get byte
  961. #if __option(mc68020)
  962.                 move.w            0(VolumeMap,Temp2.L*2),Temp    ;getting volume corrected value
  963. #else
  964.                 lsl.l                #1,Temp2
  965.                 move.w            0(VolumeMap,Temp2.L),Temp
  966. #endif
  967.                 add.w                Temp,(LocalBuffer)+    ;adding data into temporary buffer
  968.  
  969.                 add.l                Step,Pointer    ;incrementing pointer
  970.  
  971.                 dbf                    LocalCount,@3
  972.  
  973.         @OutPoint:
  974.                 move.l            Pointer,OFFSET(struct channel,pointer)(Channel)
  975.                 movem.l            (A7)+,D3-D5/A2-A4
  976.             }
  977.  
  978.         #undef Pointer
  979.         #undef Step
  980.         #undef FixLength
  981.         #undef LocalCount
  982.         #undef Temp
  983.         #undef Temp2
  984.  
  985.         #undef SampleData
  986.         #undef VolumeMap
  987.         #undef Channel
  988.         #undef SampPtr
  989.         #undef LocalBuffer
  990.     }
  991. #endif
  992.  
  993.  
  994. #if !USE_ASSEMBLY_CODE
  995. void            SampleAntiAliased8(struct channel* ch, short* Buffer, short Count)
  996.     {
  997.         long                            Pointer;
  998.         long                            FixLength;
  999.         char*                            SampleData;
  1000.         long                            Step;
  1001.         long                            LoopLength;
  1002.         short                            Volume;
  1003.         short                            LeftWeight;
  1004.         short                            RightWeight;
  1005.  
  1006.         if (ch->mode != DO_NOTHING)
  1007.             {
  1008.                 Pointer = ch->pointer;
  1009.                 FixLength = ch->samp->fix_length;
  1010.                 SampleData = ch->samp->start;
  1011.                 Step = ch->step;
  1012.                 LoopLength = ch->samp->fix_rp_length;
  1013.                 Volume = CONSTRAIN(ch->volume,MIN_VOLUME,MAX_VOLUME) - MIN_VOLUME;
  1014.              LoopPoint:
  1015.                 if (Pointer >= FixLength)
  1016.                     {
  1017.                         /* is there a replay ? */
  1018.                         if (!ch->samp->rp_start)
  1019.                             {
  1020.                                 ch->mode = DO_NOTHING;
  1021.                                 goto OutPoint;
  1022.                             }
  1023.                         ch->mode = REPLAY;
  1024.                         Pointer -= LoopLength;
  1025.                         goto LoopPoint;
  1026.                     }
  1027.                 RightWeight = Pointer & ((1 << ACCURACY) - 1);
  1028.                 LeftWeight = (1 << ACCURACY) - RightWeight;
  1029.                 *(Buffer++) +=
  1030.                     (Volume * ((LeftWeight * SampleData[fix_to_int(Pointer)])
  1031.                     + (RightWeight * SampleData[fix_to_int(Pointer) + 1])) >> (ACCURACY + 1 + 6));
  1032.                 Pointer += Step;
  1033.                 Count -= 1;
  1034.                 if (Count > 0)
  1035.                     {
  1036.                         goto LoopPoint;
  1037.                     }
  1038.              OutPoint:
  1039.                 ch->pointer = Pointer;
  1040.             }
  1041.     }
  1042. #else
  1043. void            SampleAntiAliased8(struct channel* ch, short* Buffer, short Count)
  1044.     {
  1045.         #define Pointer    D0
  1046.         #define Mask    D1
  1047.         #define Step    D2
  1048.         #define FixLength    D3
  1049.         #define LocalCount    D4
  1050.         #define Temp    D5
  1051.         #define Temp2    D6
  1052.  
  1053.         #define SampleData    A0
  1054.         #define AliasMap    A1
  1055.         #define VolumeMap    A2
  1056.         #define Channel    A3
  1057.         #define SampPtr    A4
  1058.         #define LocalBuffer    A5
  1059.  
  1060.         asm
  1061.             {
  1062.                 movem.l            D3-D6/A2-A5,-(A7)
  1063.  
  1064.                 /* loading global variables & parameters:    Must NOT disturb A5 and A6 here */
  1065.                 move.l            AliasTable,AliasMap
  1066.                 move.l            ch,Channel
  1067.                 move.w            Count,LocalCount
  1068.                 move.l            OFFSET(struct channel,volume)(Channel),Temp    ;got volume
  1069.                 cmp.l                #MIN_VOLUME,Temp
  1070.                 bge.s                @8
  1071.                 moveq.l            #0,Temp    ;if volume < 0, constrain it to 0
  1072.         @8: cmp.l                #MAX_VOLUME,Temp
  1073.                 bmi.s                @7
  1074.                 moveq.l            #MAX_VOLUME,Temp    ;if volume > max volume, constain it to max
  1075.         @7:
  1076. #if 0 != MIN_VOLUME
  1077.                 ;this bit is untested, but I think it will work.    Don't see why
  1078.                 ;MIN_VOLUME would ever be != 0, though
  1079.                 add.l                #(MIN_VOLUME * 256 * sizeof(short)),Temp    ;table starts at 0, so add this in
  1080. #endif
  1081.                 moveq                #9,Temp2
  1082.                 lsl.l                Temp2,Temp    ;multiplied by 256*sizeof(short) to obtain offset
  1083.                 move.l            SubVolumeTable,VolumeMap    ;get base address
  1084.                 add.l                Temp,VolumeMap    ;add offset
  1085.                 move.l            Buffer,LocalBuffer
  1086.                 subq.w            #1,LocalCount
  1087.                 /* loading sample things */
  1088.                 move.l            OFFSET(struct channel,samp)(Channel),SampPtr
  1089.                 move.l            OFFSET(struct sample_info,fix_length)(SampPtr),FixLength
  1090.                 move.l            OFFSET(struct sample_info,start)(SampPtr),SampleData
  1091.                 /* loading channel things */
  1092.                 move.l            OFFSET(struct channel,pointer)(Channel),Pointer
  1093.                 move.l            OFFSET(struct channel,step)(Channel),Step
  1094.  
  1095.                 /* clearing high bits of certain registers */
  1096. #if __option(mc68020)
  1097.                 ;this is an invariant optimization which is only meaningful on the 68020, so
  1098.                 ;we don't need it if we are compiling for 68000
  1099.                 clr.l                Mask
  1100. #endif
  1101.  
  1102.                 cmp.l                #DO_NOTHING,OFFSET(struct channel,mode)(Channel)
  1103.                 beq.s                @OutPoint
  1104.  
  1105.         @3: cmp.l                Pointer,FixLength
  1106.                 bhi.s                @1
  1107.                 tst.l                OFFSET(struct sample_info,rp_start)(SampPtr)
  1108.                 bne.s                @2
  1109.                 move.l            #DO_NOTHING,OFFSET(struct channel,mode)(Channel)
  1110.                 bra.s                @OutPoint
  1111.         @2: sub.l                OFFSET(struct sample_info,fix_rp_length)(SampPtr),Pointer
  1112.                 move.l            #REPLAY,OFFSET(struct channel,mode)(Channel)
  1113.                 bra.s                @3
  1114.  
  1115.         @1:
  1116.                 ;calculating anti-aliasing mask
  1117. #if !__option(mc68020)
  1118.                 moveq.l            #0,Mask    ;make sure to clear the high bits each time for 68000
  1119. #endif
  1120.                 move.w            Pointer,Mask    ;get lower 16 bits of pointer
  1121.                 and.w                #0x0f00,Mask    ;keep only upper 4 bits of fraction
  1122.                 ;this conveniently works out to leave 8 bits just below the accuracy
  1123.                 ;into which we can stuff bytes. */
  1124. #if ACCURACY != 12
  1125. #error "ACCURACY == 12 is hardwired!"
  1126. #endif
  1127.  
  1128.                 ;fetching data bytes
  1129.                 move.l            Pointer,Temp
  1130.                 moveq                #ACCURACY,Temp2
  1131.                 lsr.l                Temp2,Temp    ;now Temp is the data index
  1132.                 moveq.l            #0,Temp2
  1133.                 move.b            0(SampleData,Temp.L),Mask    ;or in left byte
  1134. #if __option(mc68020)
  1135.                 move.b            0(AliasMap,Mask.L*2),Temp2    ;got left product
  1136.                 move.b            1(SampleData,Temp.L),Mask    ;or in right byte
  1137.                 add.b                1(AliasMap,Mask.L*2),Temp2    ;added in right product
  1138.                 move.w            0(VolumeMap,Temp2.L*2),Temp    ;getting volume corrected value
  1139. #else
  1140.                 lsl.l                #1,Mask
  1141.                 move.b            0(AliasMap,Mask.L),Temp2    ;got left product
  1142.                 lsr.l                #1,Mask    ;must shift back, since we OR in a byte next
  1143.                 move.b            1(SampleData,Temp.L),Mask    ;or in right byte
  1144.                 lsl.l                #1,Mask
  1145.                 add.b                1(AliasMap,Mask.L),Temp2    ;added in right product
  1146.                 lsl.l                #1,Temp2
  1147.                 move.w            0(VolumeMap,Temp2.L),Temp    ;getting volume corrected value
  1148. #endif
  1149.                 add.w                Temp,(LocalBuffer)+    ;adding data into temporary buffer
  1150.  
  1151.                 add.l                Step,Pointer    ;incrementing pointer
  1152.  
  1153.                 dbf                    LocalCount,@3
  1154.  
  1155.         @OutPoint:
  1156.                 move.l            Pointer,OFFSET(struct channel,pointer)(Channel)
  1157.                 movem.l            (A7)+,D3-D6/A2-A5
  1158.             }
  1159.  
  1160.         #undef Pointer
  1161.         #undef Mask
  1162.         #undef Step
  1163.         #undef FixLength
  1164.         #undef LocalCount
  1165.         #undef Temp
  1166.         #undef Temp2
  1167.  
  1168.         #undef SampleData
  1169.         #undef AliasMap
  1170.         #undef VolumeMap
  1171.         #undef Channel
  1172.         #undef SampPtr
  1173.         #undef LocalBuffer
  1174.     }
  1175. #endif
  1176.  
  1177.  
  1178. /* Same as SampleAliased8 except it doesn't divide out the volume */
  1179. void            SampleAliased16(struct channel* ch, short* Buffer, short Count)
  1180.     {
  1181.         long                Pointer;
  1182.         long                FixLength;
  1183.         char*                SampleData;
  1184.         long                Step;
  1185.         long                LoopLength;
  1186.         short                Volume;
  1187.  
  1188.         if (ch->mode != DO_NOTHING)
  1189.             {
  1190.                 Pointer = ch->pointer;
  1191.                 FixLength = ch->samp->fix_length;
  1192.                 SampleData = ch->samp->start;
  1193.                 Step = ch->step;
  1194.                 LoopLength = ch->samp->fix_rp_length;
  1195.                 Volume = CONSTRAIN(ch->volume,MIN_VOLUME,MAX_VOLUME) - MIN_VOLUME;
  1196.              LoopPoint:
  1197.                 if (Pointer >= FixLength)
  1198.                     {
  1199.                         /* is there a replay ? */
  1200.                         if (!ch->samp->rp_start)
  1201.                             {
  1202.                                 ch->mode = DO_NOTHING;
  1203.                                 goto OutPoint;
  1204.                             }
  1205.                         ch->mode = REPLAY;
  1206.                         Pointer -= LoopLength;
  1207.                         goto LoopPoint;
  1208.                     }
  1209.                 /* placing result in buffer -- ranges between 64*-128 .. 64*128. */
  1210.                 /* that way we can add two channels to get 15 bits worth of stuff */
  1211.                 /* or 4 channels for 16 bits worth of stuff */
  1212.                 *(Buffer++) += Volume * SampleData[fix_to_int(Pointer)];
  1213.                 Pointer += Step;
  1214.                 Count -= 1;
  1215.                 if (Count > 0)
  1216.                     {
  1217.                         goto LoopPoint;
  1218.                     }
  1219.              OutPoint:
  1220.                 ch->pointer = Pointer;
  1221.             }
  1222.     }
  1223.  
  1224.  
  1225. /* Same as SampleAntiAliased8 except it doesn't divide out the volume */
  1226. void            SampleAntiAliased16(struct channel* ch, short* Buffer, short Count)
  1227.     {
  1228.         long                            Pointer;
  1229.         long                            FixLength;
  1230.         char*                            SampleData;
  1231.         long                            Step;
  1232.         long                            LoopLength;
  1233.         short                            Volume;
  1234.         short                            LeftWeight;
  1235.         short                            RightWeight;
  1236.  
  1237.         if (ch->mode != DO_NOTHING)
  1238.             {
  1239.                 Pointer = ch->pointer;
  1240.                 FixLength = ch->samp->fix_length;
  1241.                 SampleData = ch->samp->start;
  1242.                 Step = ch->step;
  1243.                 LoopLength = ch->samp->fix_rp_length;
  1244.                 Volume = CONSTRAIN(ch->volume,MIN_VOLUME,MAX_VOLUME) - MIN_VOLUME;
  1245.              LoopPoint:
  1246.                 if (Pointer >= FixLength)
  1247.                     {
  1248.                         /* is there a replay ? */
  1249.                         if (!ch->samp->rp_start)
  1250.                             {
  1251.                                 ch->mode = DO_NOTHING;
  1252.                                 goto OutPoint;
  1253.                             }
  1254.                         ch->mode = REPLAY;
  1255.                         Pointer -= LoopLength;
  1256.                         goto LoopPoint;
  1257.                     }
  1258.                 RightWeight = Pointer & ((1 << ACCURACY) - 1);
  1259.                 LeftWeight = (1 << ACCURACY) - RightWeight;
  1260.                 /* placing result in buffer -- ranges between 64*-128 .. 64*128. */
  1261.                 /* that way we can add two channels to get 15 bits worth of stuff */
  1262.                 /* or 4 channels for 16 bits worth of stuff */
  1263.                 *(Buffer++) +=
  1264.                     (Volume * (((LeftWeight * SampleData[fix_to_int(Pointer)])
  1265.                     + (RightWeight * SampleData[fix_to_int(Pointer) + 1])) >> (ACCURACY + 1)));
  1266.                 Pointer += Step;
  1267.                 Count -= 1;
  1268.                 if (Count > 0)
  1269.                     {
  1270.                         goto LoopPoint;
  1271.                     }
  1272.              OutPoint:
  1273.                 ch->pointer = Pointer;
  1274.             }
  1275.     }
  1276.